package com.example.onlinemonitoring.Iec104.util;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import com.example.onlinemonitoring.Iec104.enums.TypeIdentifierEnum;
import com.example.onlinemonitoring.Iec104.enums.UControlEnum;
import com.example.onlinemonitoring.Iec104.message.MessageDetail;
import com.example.onlinemonitoring.Iec104.other.TeleSignallingInfoEntity;

/**
 * 
 * @ClassName: Iec104Util
 * @Description: 工具类
 * @author YDL
 * @date 2020年5月13日
 */
public class Iec104Util {

	private static int controlLength = 4;

	/**
	 * I 格式 低位在前
	 * 
	 * @param accept 接收序列号
	 * @param send   发送序列号
	 * @return
	 */
	public static byte[] getIcontrol(short accept, short send) {
		byte[] control = new byte[4];
		// 向左移动一位 保证低位的D0 是0
		send = (short) (send << 1);
		control[0] = (byte) ((send));
		control[1] = (byte) ((send >> 8));
		accept = (short) (accept << 1);
		control[2] = (byte) ((accept));
		control[3] = (byte) ((accept >> 8));
		return control;
	}

	/**
	 * 返回控制域中的接收序号
	 * 
	 * @param control
	 * @return
	 */
	public static short getAccept(byte[] control) {
		int accept = 0;
		short acceptLow = (short) (control[2] & 0xff);
		short acceptHigh = (short) (control[3] & 0xff);
		accept += acceptLow;
		accept += acceptHigh << 8;
		accept = accept >> 1;
		return (short) accept;

	}

	/**
	 * 返回控制域中的发送序号
	 * 
	 * @param control
	 * @return
	 */
	public static short getSend(byte[] control) {
		int send = 0;
		short acceptLow = (short) (control[0] & 0xff);
		short acceptHigh = (short) (control[1] & 0xff);
		send += acceptLow;
		send += acceptHigh << 8;
		send = send >> 1;
		return (short) send;
	}

	/**
	 * S 格式
	 * 
	 * @param accept
	 * @return
	 */
	public static byte[] getScontrol(short accept) {
		byte[] control = new byte[4];
		// 向左移动一位 保证低位的D0 是0
		short send = 1;
		control[0] = (byte) ((send));
		control[1] = (byte) ((send >> 8));
		accept = (short) (accept << 1);
		control[2] = (byte) ((accept));
		control[3] = (byte) ((accept >> 8));
		return control;
	}

	/**
	 * 
	 * @Title: 返回U帧
	 * @Description: 判断是否是
	 * @param @param  control
	 * @param @return
	 * @return boolean
	 * @throws
	 */
	public static UControlEnum getUcontrol(byte[] control) {
		if (control.length < controlLength || control[1] != 0 || control[3] != 0 || control[2] != 0) {
			return null;
		}
		int controlInt = ByteUtil.byteArrayToInt(control);
		for (UControlEnum ucontrolEnum : UControlEnum.values()) {
			if (ucontrolEnum.getValue() == controlInt) {
				return ucontrolEnum;
			}
		}
		return null;
	}

	/**
	 * 解析地址域
	 *
	 * @param low  第一个地址
	 * @param high 第二个地址
	 * @return
	 */
	public static String address(int low, int high) {

		String lowString = String.format("%02X", low);
		String highString = String.format("%02X", high);

		return highString + lowString;
	}

	/**
	 * int转换成16进制字符串 不需要0x
	 *
	 * @param b 需要转换的int值
	 * @return 16进制的String
	 */
	public static String toHexStringNo0x(int b) {
		String hex = Integer.toHexString(b & 0xFF);
		if (hex.length() == 1) {
			hex = '0' + hex;
		}
		return hex.toUpperCase();
	}

	/**
	 * 返回消息地址 其中低位在前
	 * 
	 * @param i
	 * @return
	 */
	public static byte[] intToMessageAddress(int i) {
		byte[] result = new byte[3];
		result[0] = (byte) (i & 0xFF);
		result[1] = (byte) ((i >> 8) & 0xFF);
		result[2] = (byte) ((i >> 16) & 0xFF);
		return result;
	}

	/**
	 * int转换成16进制字符串
	 *
	 * @param b 需要转换的int值
	 * @return 16进制的String
	 */
	public static String toHexString(int b) {
		String hex = Integer.toHexString(b & 0xFF);
		if (hex.length() == 1) {
			hex = '0' + hex;
		}
		return "0x" + hex.toUpperCase();
	}

	/**
	 * 消息地址 只有三个
	 * 
	 * @param bytes
	 * @return
	 */
	public static int messageAddressToInt(byte[] bytes) {
		int value = 0;
		for (int i = 2; i >= 0; i--) {
			int shift = (2 - i) * 8;
			value += (bytes[2 - i] & 0xFF) << shift;
		}
		return value;
	}

	/**
	 * 设置可以变限定词
	 * 
	 * @param ruleDetail104
	 * @param byteItem
	 */
	public static void setChanged(MessageDetail ruleDetail104, byte byteItem) {
		// 第一位是 0 则是有序的
		ruleDetail104.setContinuous((byteItem & 0x80) == 0 ? false : true);
		// 先将第一位数置零 然后转换成int
		ruleDetail104.setMeasgLength(byteItem & (byte) 0x7F);
	}

	/**
	 * 返回可变限定词数组
	 * 
	 * @param ruleDetail104
	 * @return
	 */
	public static byte getChangedQualifiers(MessageDetail ruleDetail104) {
		// 将长度转换成 byte
		byte changedQualifiers = (byte) ruleDetail104.getMeasgLength();
		// 判断SQ 置 isContinuous false SQ = 0;否则 SQ =1 , 同时将SQ置 设置在 可变限定词的 D7位置
		int sq = ruleDetail104.isContinuous() ? 0x80 : 0;
		changedQualifiers = (byte) (sq | changedQualifiers);
		return changedQualifiers;
	}

	public static void setMeaageAttribute(MessageDetail ruleDetail104) {
		boolean isMessage = !(TypeIdentifierEnum.generalCall.equals(ruleDetail104.getTypeIdentifier()) // 总召唤无此项
				|| TypeIdentifierEnum.timeSynchronization.equals(ruleDetail104.getTypeIdentifier()) // 时钟同步
				|| TypeIdentifierEnum.resetPprocess.equals(ruleDetail104.getTypeIdentifier()) // 复位进程
				|| TypeIdentifierEnum.initEnd.equals(ruleDetail104.getTypeIdentifier()));
		ruleDetail104.setMessage(isMessage);

		boolean isQualifiers = !(TypeIdentifierEnum.timeSynchronization.equals(ruleDetail104.getTypeIdentifier()) // 时钟同步
				|| TypeIdentifierEnum.onePointTeleindication.equals(ruleDetail104.getTypeIdentifier()) // 单点摇信
				|| TypeIdentifierEnum.twoPointTeleindication.equals(ruleDetail104.getTypeIdentifier()) // 双点摇信
				|| TypeIdentifierEnum.onePointTelecontrol.equals(ruleDetail104.getTypeIdentifier()) // 单命令遥控
				|| TypeIdentifierEnum.twoPointTelecontrol.equals(ruleDetail104.getTypeIdentifier())); // 双命令遥控
		ruleDetail104.setQualifiers(isQualifiers);
		boolean isTimeScale = TypeIdentifierEnum.timeSynchronization.equals(ruleDetail104.getTypeIdentifier()) // 时钟同步
				|| TypeIdentifierEnum.onePointTimeTeleindication.equals(ruleDetail104.getTypeIdentifier()) // 摇信带时标 单点
				|| TypeIdentifierEnum.twoPointTimeTeleindication.equals(ruleDetail104.getTypeIdentifier()); // 摇信带时标 双点
		ruleDetail104.setTimeScaleExit(isTimeScale);
	}

	/**
	 * short 转换成两个 字节后是163 00 也就是 value[1] 中才有值
	 * test 在D7位置 因此 值应该和 01000000 做与运算
	 * P/N 0肯定确认 1否定确认
	 * 
	 * @return 肯定或否定确认
	 */
	public static boolean isYes(byte[] values) {
		return (values[0] & 1 << 6) == 0;
	}

	/**
	 * short 转换成两个 字节后是163 00 也就是 value[1] 中才有值
	 * test 在D7位置 因此 值应该和 10000000 做与运算
	 * tets 0 为试验 1 试验
	 * 
	 * @return 是否试验
	 */
	public static boolean isTets(byte[] values) {
		return (values[0] & 1 << 7) != 0;
	}

	/**
	 * 返回具体的原因
	 * 
	 * @param values
	 * @return
	 */
	public static short getTransferReasonShort(byte[] values) {
		byte transferReason = values[0];
		// 前两位置零
		transferReason = (byte) (transferReason & 0x3E);
		return transferReason;
	}

	public static short getTransferReasonShort(boolean isTets, boolean isYes, short transferReason) {
		int t = isTets ? 1 : 0;
		int y = isYes ? 0 : 1;
		int transferReasonInt = t << 7 | transferReason;
		transferReasonInt = y << 6 | transferReasonInt;

		short transferReasonShort = (short) (transferReasonInt << 8);
		return transferReasonShort;
	}

	/**
	 * 返回终端地址对应的byte数组 其中低位在前
	 * 
	 * @param terminalAddress
	 * @return
	 */
	public static byte[] getTerminalAddressByte(short terminalAddress) {
		byte[] b = new byte[2];
		b[1] = (byte) ((terminalAddress >> 8) & 0xff);
		b[0] = (byte) (terminalAddress & 0xff);
		return b;
	}

	/**
	 * 时标CP56Time2a解析
	 *
	 * @param b 时标CP56Time2a（长度为7 的int数组）
	 * @return 解析结果
	 */
	public static String TimeScale(int b[], TeleSignallingInfoEntity teleSignallingInfoEntity) {

		String str = "";
		int year = (b[6] & 0x7F) + 2000;
		int month = b[5] & 0x0F;
		int day = b[4] & 0x1F;
		int week = (b[4] & 0xE0) / 32;
		int hour = b[3] & 0x1F;
		int minute = b[2] & 0x3F;
		int second = (b[1] << 8) + b[0];
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.YEAR, year);
		calendar.set(Calendar.MONTH, month);
		calendar.set(Calendar.DATE, day);
		calendar.set(Calendar.HOUR, hour);
		calendar.set(Calendar.MINUTE, minute);
		calendar.set(Calendar.SECOND, second / 1000);
		Date date = calendar.getTime();
		teleSignallingInfoEntity.setTime(date);
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println(simpleDateFormat.format(date));
		str += "时标CP56Time2a:" + year + "-"
				+ String.format("%02d", month) + "-"
				+ String.format("%02d", day) + "," + hour + ":" + minute + ":"
				+ second / 1000 + "." + second % 1000;
		return str + "\n";
	}

	/**
	 * 返回回终端地址 其中低位在前
	 * 
	 * @param terminalAddress
	 * @return
	 */
	public static short getTerminalAddressShort(byte[] terminalAddress) {
		short value = 0;
		value += (terminalAddress[0] & 0xFF);
		value += (terminalAddress[1] & 0xFF) << 8;
		return value;
	}

	/**
	 * 16进制表示的字符串转换为字节数组
	 *
	 * @param s 16进制表示的字符串
	 * @return byte[] 字节数组
	 */
	public static int[] hexStringToIntArray(String s) {
		int len = s.length();
		int[] b = new int[len / 2];
		for (int i = 0; i < len; i += 2) {
			// 两位一组，表示一个字节,把这样表示的16进制字符串，还原成一个字节
			b[i / 2] = (int) ((Character.digit(s.charAt(i), 16) << 4) + Character
					.digit(s.charAt(i + 1), 16));
		}
		return b;
	}
}
